import 'dart:async';
import 'dart:io';

import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:fluttercommon/fluttercommon.dart';
import 'package:fluttertoast/fluttertoast.dart';

import '../http/http_configs.dart';
import '../http/http_wrapper.dart';
import '../widgets/http_request_loading.dart';

typedef Future<void> ShowAlertFunction(
  BuildContext context, {
  String? titleText,
  String? actionLabel,
  String? message,
  Widget? content,
  bool? supportCupertinoStyle,
  TextStyle? messageStyle,
});

typedef Future<bool> ShowConfirmDialogFunction(
  BuildContext context, {
  String? message,
  Widget? content,
  String? titleText,
  String? confirmLabel,
  String? cancelLabel,
  bool? canCancel,
  bool? supportCupertinoStyle,
  TextStyle? messageStyle,
});

extension BuildContextExtentions on BuildContext {
  Future<bool?> showToast(
    String msg, {
    Toast toastLength = Toast.LENGTH_SHORT,
    int timeInSecForIosWeb = 1,
    double fontSize = 16.0,
    ToastGravity gravity = ToastGravity.CENTER,
    Color backgroundColor = Colors.black,
    Color textColor = Colors.white,
  }) {
    return Fluttertoast.showToast(
      msg: msg,
      toastLength: toastLength,
      gravity: gravity,
      timeInSecForIosWeb: timeInSecForIosWeb,
      backgroundColor: backgroundColor,
      textColor: textColor,
      fontSize: fontSize,
    );
  }

  Future<bool?> cancelToast() {
    return Fluttertoast.cancel();
  }

  void showSnackBar(
    String message, {
    backgroundColor: Colors.amber,
    int seconds = 2,
  }) {
    var finalMessage = message;
    if (message.length > 100) {
      finalMessage = message.substring(0, 100);
    }
    ScaffoldMessenger.of(this).showSnackBar(SnackBar(
      content: Text(finalMessage),
      backgroundColor: backgroundColor,
      duration: Duration(seconds: seconds),
    ));
  }

  Future<void> showAlert({
    String? titleText,
    String? actionLabel,
    String? message,
    Widget? content,
    bool supportCupertinoStyle = false,
    TextStyle? messageStyle,
  }) {
    if ((message?.isEmpty ?? true) && content == null) return Future.value();
    actionLabel ??= CustomizableFeatures.strings.confirm;
    if (CustomizableFeatures.showAlertFunction != null) {
      return CustomizableFeatures.showAlertFunction!(
        this,
        titleText: titleText,
        actionLabel: actionLabel,
        message: message,
        content: content,
        supportCupertinoStyle: supportCupertinoStyle,
      );
    }
    if (supportCupertinoStyle == true && Platform.isIOS)
      return _showIosStyleAlert(
        titleText: titleText,
        actionLabel: actionLabel,
        message: message,
        content: content,
      );
    return showDialog(
        context: this,
        builder: (context) {
          return AlertDialog(
            title: titleText?.isNotEmpty == true ? Text(titleText!) : null,
            content: content ??
                Text(
                  message ?? "???",
                  style: messageStyle,
                ),
            actions: <Widget>[
              ElevatedButton(
                onPressed: () {
                  Navigator.of(context).pop();
                },
                child: Text(
                  actionLabel!,
                  style: TextStyle(color: Colors.white),
                ),
              )
            ],
          );
        });
  }

  Future<bool?> showConfirmDialog({
    String? message,
    Widget? content,
    String? titleText,
    String? confirmLabel,
    String? cancelLabel,
    bool canCancel = true,
    bool supportCupertinoStyle = false,
    TextStyle? messageStyle,
  }) {
    confirmLabel ??= CustomizableFeatures.strings.confirm;
    cancelLabel ??= CustomizableFeatures.strings.cancel;
    if (CustomizableFeatures.showConfirmDialogFunction != null) {
      return CustomizableFeatures.showConfirmDialogFunction!(
        this,
        message: message,
        content: content,
        titleText: titleText,
        confirmLabel: confirmLabel,
        cancelLabel: cancelLabel,
        canCancel: canCancel,
        supportCupertinoStyle: supportCupertinoStyle,
      );
    }

    if (supportCupertinoStyle == true && Platform.isIOS)
      return _showIosStyleConfirmDialog(
        message: message,
        content: content,
        titleText: titleText,
        confirmLabel: confirmLabel,
        cancelLabel: cancelLabel,
        canCancel: canCancel,
      );
    return showDialog(
        context: this,
        barrierDismissible: canCancel,
        builder: (context) {
          return AlertDialog(
            title: titleText != null ? Text(titleText) : null,
            content: content ?? Text(message ?? "", style: messageStyle),
            actions: <Widget>[
              TextButton(
                onPressed: () {
                  Navigator.of(context).pop(false);
                },
                child: Text(cancelLabel!),
              ),
              ElevatedButton(
                child: Text(
                  confirmLabel!,
                  style: TextStyle(color: Colors.white),
                ),
                onPressed: () {
                  Navigator.of(context).pop(true);
                },
              )
            ],
          );
        });
  }

  Future<void> _showIosStyleAlert({
    String? titleText,
    String? actionLabel,
    String? message,
    Widget? content,
  }) {
    actionLabel ??= CustomizableFeatures.strings.confirm;
    return showDialog(
        context: this,
        builder: (context) {
          return CupertinoAlertDialog(
            title: titleText != null ? Text(titleText) : null,
            content: content ??
                Text(
                  message ?? "???",
                  style: Theme.of(context).textTheme.bodyText2,
                ),
            actions: <Widget>[
              CupertinoDialogAction(
                onPressed: () {
                  Navigator.of(context).pop();
                },
                child: Text(actionLabel!),
              )
            ],
          );
        });
  }

  Future<bool?> _showIosStyleConfirmDialog({
    String? message,
    Widget? content,
    String? titleText,
    String? confirmLabel,
    String? cancelLabel,
    bool canCancel = true,
  }) {
    confirmLabel ??= CustomizableFeatures.strings.confirm;
    cancelLabel ??= CustomizableFeatures.strings.cancel;
    return showDialog(
        context: this,
        barrierDismissible: canCancel,
        builder: (context) {
          return CupertinoAlertDialog(
            title: titleText != null ? Text(titleText) : null,
            content: content ?? Text(message ?? ""),
            actions: <Widget>[
              CupertinoDialogAction(
                onPressed: () {
                  Navigator.of(context).pop(false);
                },
                child: Text(cancelLabel!),
              ),
              CupertinoDialogAction(
                child: Text(confirmLabel!),
                onPressed: () {
                  Navigator.of(context).pop(true);
                },
              )
            ],
          );
        });
  }

  Future<ApiResult> sendRequest(
    Future<ApiResult> request, {
    bool showErrorMessage = true,
    String? loadingText,
    Widget? waitingWidget,
    bool enableBackKey = true,
    int delayInMilliseconds = 1,
  }) async {
    ApiResult? apiResult;
    bool isShow = false;
    loadingText ??= CustomizableFeatures.strings.please_wait;
    Future.delayed(Duration(milliseconds: delayInMilliseconds), () {
      if (apiResult == null) {
        isShow = true;
        showDialog(
            context: this,
            barrierDismissible: false,
            builder: (context) {
              return WillPopScope(
                onWillPop: () async => enableBackKey,
                child: StreamBuilder<ApiResult?>(
                  stream: Stream.periodic(Duration(milliseconds: 100), (count) {
                    return apiResult;
                  }),
                  builder: (BuildContext context, AsyncSnapshot snapshot) {
                    debugPrint('snapshot is ${snapshot.toString()}');
                    if (snapshot.hasData || snapshot.hasError) {
                      if (isShow) {
                        isShow = false;
                        Future.delayed(Duration.zero, () {
                          Navigator.of(context).pop();
                        });
                      }
                    }

                    return SimpleDialog(
                      backgroundColor: Colors.transparent,
                      children: <Widget>[
                        waitingWidget ??
                            CustomizableFeatures.waitingWidget ??
                            LoadingWidget(loadingText: loadingText)
                      ],
                    );
                  },
                ),
              );
            });
      }
    });

    try {
      apiResult = await request;
    } catch (e) {
      apiResult = ApiResult.fakeResult(0, e.toString());
    }

    if (isShow) {
      isShow = false;
      Navigator.of(this).pop();
    }

    if (showErrorMessage == true && apiResult.success() == false) {
      String message = apiResult.message();
      if (message.length > 100) {
        message = message.substring(0, 99);
      }
      await showAlert(message: message);
    }

    return apiResult;
  }

  Future<T?> goto<T extends Object>(Widget page) {
    try {
      return Navigator.of(this)
          .push<T>(MaterialPageRoute(builder: (BuildContext context) => page));
    } catch (e) {
      ///ignore any error
      return Future.value(null);
    }
  }

  void pop<T extends Object>([T? result]) {
    Navigator.of(this).pop(result);
  }

  void popNTimes(int x) {
    if (x >= 1) {
      int i = x;
      Navigator.of(this).popUntil((route) {
        return i-- <= 0;
      });
    }
  }

  bool isKeyboardDisplayed() => MediaQuery.of(this).viewInsets.bottom > 50.0;

  void hideKeyboard() {
    FocusManager.instance.primaryFocus?.unfocus();
  }

  String imageAsset(String name) {
    final configs = Configs.of(this);
    if (name.contains(".")) {
      return "${configs.imageRoot}/$name";
    } else {
      return "${configs.imageRoot}/$name.png";
    }
  }
}

VoidCallback _showWaitingDialog(
  BuildContext context, {
  String? loadingText,
  Widget? waitingWidget,
  bool enableBackKey = true,
}) {
  loadingText ??= CustomizableFeatures.strings.please_wait;
  showDialog(
    context: context,
    barrierDismissible: false,
    builder: (context) {
      return WillPopScope(
        onWillPop: () async => enableBackKey,
        child: SimpleDialog(
          backgroundColor: Colors.transparent,
          children: <Widget>[
            waitingWidget ??
                CustomizableFeatures.waitingWidget ??
                LoadingWidget(loadingText: loadingText)
          ],
        ),
      );
    },
  );
  return () => Navigator.of(context).pop();
}

Future<dynamic> waitingTask(
  BuildContext context,
  Future<dynamic> task, {
  String? loadingText,
  Widget? waitingWidget,
  bool enableBackKey = true,
  int delayInMilliseconds = 0,
}) async {
  Timer? timer;
  VoidCallback? closeDialog;
  if (delayInMilliseconds > 0) {
    timer = Timer(Duration(milliseconds: delayInMilliseconds), () {
      closeDialog = _showWaitingDialog(
        context,
        loadingText: loadingText,
        waitingWidget: waitingWidget,
        enableBackKey: enableBackKey,
      );
    });
  } else {
    closeDialog = _showWaitingDialog(
      context,
      loadingText: loadingText,
      waitingWidget: waitingWidget,
      enableBackKey: enableBackKey,
    );
  }

  task.whenComplete(() {
    closeDialog?.call();
  });

  await task;

  timer?.cancel();

  return task;
}
